package com.tanhua.server.server;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSON;
import com.tanhua.autoconfig.templates.OssTemplate;
import com.tanhua.commons.utils.Constants;
import com.tanhua.dubbo.api.CommentsServiceApi;
import com.tanhua.dubbo.api.MovementApi;
import com.tanhua.dubbo.api.MovementTimeLineApi;
import com.tanhua.dubbo.api.UserInfoApi;
import com.tanhua.model.db.User;
import com.tanhua.model.db.UserInfo;
import com.tanhua.model.mongo.Comment;
import com.tanhua.model.mongo.Movement;
import com.tanhua.model.mongo.MovementTimeLine;
import com.tanhua.model.vo.MovementsVo;
import com.tanhua.model.vo.PageResult;
import com.tanhua.server.interceptor.UserHolder;
import org.apache.dubbo.config.MonitorConfig;
import org.apache.dubbo.config.annotation.DubboReference;
import org.apache.dubbo.config.annotation.DubboService;
import org.bouncycastle.pqc.math.linearalgebra.PolynomialRingGF2;
import org.bson.types.ObjectId;
import org.checkerframework.checker.units.qual.A;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.mongodb.core.aggregation.ArrayOperators;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

@Service
public class MovementsService {
    @DubboReference
    private MovementApi movementApi;
    @Autowired
    private OssTemplate ossTemplate;
    @Autowired
    private StringRedisTemplate redisTemplate;
    @Autowired   //核心类private RabbitTemplate amqpTemplate;，，用mqMessageService封装
    private MqMessageService mqMessageService;
    @DubboReference
    private UserInfoApi userInfoApi;
    @DubboReference
    private MovementTimeLineApi movementTimeLineApi;
    @DubboReference
    private CommentsServiceApi commentsServiceApi;
    //发布动态
    public void sendMovement(MultipartFile[] imageContent, String textContent, String location, String longitude, String latitude) throws IOException {
       //构建动态对象
        Movement movement = new Movement();
        //获取页面动态数据，构造动态对象
        movement.setUserId(UserHolder.getUserId());
        movement.setTextContent(textContent);
        movement.setLocationName(location);
        movement.setLongitude(longitude);
        movement.setLatitude(latitude);
        movement.setCreated(System.currentTimeMillis());
        //上传图片到阿里云在保存到动态表
        ArrayList<String> medias = new ArrayList<>();
        for (MultipartFile multipartFile : imageContent) {
            String url = ossTemplate.uploadFile(multipartFile.getInputStream(), multipartFile.getOriginalFilename());
            medias.add(url);
        }
        movement.setMedias(medias);
        //调用api保存
       String movementId = movementApi.saveMovement(movement);
       //map集合传递需要手动转json，也可以直接传string，远程调用保存movement时，消费者不会自动获取id，因为经过序列化为byte传输
        //消费者和服务者两边不是一个对象,,,string和json的string有区别
        mqMessageService.sendAudiMessage(movementId);

    }
  //查询自己动态
    public PageResult findAll(Integer page, Integer pageSize, Long userId) {
        //查询自己动态和用户信息
        List<Movement> movements = movementApi.findAll(page,pageSize,userId);
        //没动态直接返回结果
        if (CollectionUtil.isEmpty(movements)){
            return new PageResult();
        }
        //有动态，循环构建vo对象组装分页结果
             //根据用户id查询用户信息
        UserInfo info = userInfoApi.findById(userId);
        List<MovementsVo> movementsVos = new ArrayList<>();
        for (Movement movement : movements) {
            MovementsVo vo = MovementsVo.init(info, movement);
            //从redis中查询点赞状态，如果有点赞状态，设置为1
            String redisKey = Constants.MOVEMENTS_INTERACT_KEY+ vo.getId();
            String hashKey = Constants.MOVEMENT_LIKE_HASHKEY+UserHolder.getUserId();

            //判断redis中是否存在某条点赞记录，，查询redis的是自己的某条动态，看redis是否存在自己点赞的hashkey
            //查看redis中是否存在喜欢的状态记录，存在则设置为1
            Boolean hasKey = redisTemplate.opsForHash().hasKey(redisKey, hashKey);
            if (hasKey){
                vo.setHasLiked(1);

            }
            String loveHashKey = Constants.MOVEMENT_LOVE_HASHKEY+UserHolder.getUserId();
            Boolean hasKey1 = redisTemplate.opsForHash().hasKey(redisKey, loveHashKey);
            if (hasKey1){
                vo.setHasLoved(1);
            }
            movementsVos.add(vo);
        }
        PageResult pageResult = new PageResult(page, pageSize, 0l, movementsVos);
        return pageResult;
    }
 //查好友动态
    public PageResult friendsMovement(Integer page,Integer pageSize) {
        //获取当前用户id，是查关系表的friendId的条件，查出动态id，
        Long userId = UserHolder.getUserId();
        List<Movement> movements = movementApi.friendsMovement(page,pageSize,userId);
        PageResult pageResult = initPage(movements, page, pageSize);
        return pageResult;
    }
//查推荐动态
    public PageResult findRecommend(Integer page, Integer pageSize) {
        Long userId = UserHolder.getUserId();
        //1.根据当前用户id从redis中查询推荐列表，如果不存在，则构建默认推荐列表，随机从mongodb提取
        String recommendIds = redisTemplate.opsForValue().get("MOVEMENTS_RECOMMEND_" + userId);
        //2.判断动态数据是否存在
       List<Movement> movements = new ArrayList<Movement>();
        if (!StrUtil.isEmpty(recommendIds)){ //存在则获取所有id，根据动态id列表查询动态详情
            String[] ids = recommendIds.split(",");
            movements = movementApi.findByIds(ids,page,pageSize);
        }else {  //数据不存在，调api随机查询动态列表
         movements = movementApi.randomMovement(pageSize);
        }

        //3.调用公共方法，传入movment列表，查询出userInfo并构建movementvo对象给页面返回动态列表
        PageResult pageResult = initPage(movements, page, pageSize);
        return pageResult;
    }
    //提取公共方法：根据用户id，查询用户详细信息
    private PageResult initPage(List<Movement> movements,Integer page,Integer pageSize){
        //判空
        if(CollectionUtil.isEmpty(movements)){
            return new PageResult();
        }
        //优化，频繁循环dubbo调用查找用户信息，浪费资源，提取出所有id，一次性查询
        //提取list中所有动态发布人id
        List<Long> ids = CollUtil.getFieldValues(movements, "userId", Long.class);
        //调用UserInfoApi，查询多个用户的用户信息,用list接收结果不好取值，用map接收
        Map<Long,UserInfo> map = userInfoApi.findIds(ids);
        List<MovementsVo> movementsVos = new ArrayList<>();
        for (Movement movement : movements) {
            Long userId1 = movement.getUserId();//获取动态发布人
            // UserInfo info = userInfoApi.findById(userId1);
            UserInfo info = map.get(userId1);
            //调movementvo工具方法的init构建
            MovementsVo vo = MovementsVo.init(info, movement);
            //从redis中查询点赞状态，如果有点赞状态，设置为1
            String redisKey = Constants.MOVEMENTS_INTERACT_KEY+ vo.getId();
            String hashKey = Constants.MOVEMENT_LIKE_HASHKEY+UserHolder.getUserId();

            //判断redis中是否存在某条点赞记录，，查询redis的是自己的某条动态，看redis是否存在自己点赞的hashkey
            Boolean hasKey = redisTemplate.opsForHash().hasKey(redisKey, hashKey);
            if (hasKey){
                vo.setHasLiked(1);
            }
            String loveHashKey = Constants.MOVEMENT_LOVE_HASHKEY+UserHolder.getUserId();
            Boolean hasKey1 = redisTemplate.opsForHash().hasKey(redisKey, loveHashKey);
            if (hasKey1){
                vo.setHasLoved(1);
            }
            movementsVos.add(vo);
        }
        return new PageResult(page,pageSize,0l,movementsVos);
    }
  //根据id查询动态
    public MovementsVo findById(String id) {
      //调用api查询动态
        Movement movement = movementApi.findById(id);
        //获取动态发布人
        Long userId = movement.getUserId();
        UserInfo info = userInfoApi.findById(userId);
        //动态转化vo
        return MovementsVo.init(info,movement);
    }
  //点赞
    public Integer like(String id) {
        //调api保存互动数据，更新动态表
        Integer commentType = 1;
        Comment comment = new Comment();
        comment.setPublishId(new ObjectId(id));
        comment.setCommentType(commentType);
        comment.setUserId(UserHolder.getUserId());  //评论人，操作人id
        comment.setCreated(System.currentTimeMillis());
        Integer likeCount = commentsServiceApi.saveComment(comment);  //save方法需要修改为通用的,更改字段不同，返回值的字段不同
        //把点赞状态存入redis，为了方便查询点赞状态
        String redisKey = Constants.MOVEMENTS_INTERACT_KEY +id;
        String hashKey = Constants.MOVEMENT_LIKE_HASHKEY + UserHolder.getUserId();
        redisTemplate.opsForHash().put(redisKey,hashKey,"1");
        //以点赞动态为例，发送日志消息，以便推荐   用户id，日志类型，路由键，业务id
        mqMessageService.sendLogMessage(UserHolder.getUserId(),"0203","log.movement",id);
        return likeCount;
    }
//取消点赞
    public Integer dislike(String id) {
        Integer commentType = 1;
        Long userId = UserHolder.getUserId();
        //1.调用api删除互动数据(comment数据表)，更新动态表（根据用户id，动态id，操作类型定位）
        Integer count = commentsServiceApi.delete(commentType,userId,id);
        //2.删除redis中的点赞状态
        String redisKey = Constants.MOVEMENTS_INTERACT_KEY +id;
        String hashKey = Constants.MOVEMENT_LIKE_HASHKEY + UserHolder.getUserId();
        redisTemplate.opsForHash().delete(redisKey,hashKey);  //删除本用户对应的某动态的点赞状态
        return count;
    }
    //喜欢
    public Integer love(String id) {
        //更新comment的互动数据
        Integer commentType = 3;
        Comment comment = new Comment();
        comment.setCreated(System.currentTimeMillis());
        comment.setCommentType(commentType);
        comment.setPublishId(new ObjectId(id));//动态id
        comment.setUserId(UserHolder.getUserId());  //传入当前用户id，，，发布人id由api端传入
        Integer count = commentsServiceApi.saveComment(comment);
        String redisKey = Constants.MOVEMENTS_INTERACT_KEY+id; //点赞和喜欢用同一个redis  key
        String hashKey = Constants.MOVEMENT_LOVE_HASHKEY+UserHolder.getUserId();
        redisTemplate.opsForHash().put(redisKey,hashKey,"1"); //redisKey hashKey hashValue
        return count;
    }
  //取消喜欢
    public Integer unlove(String id) {
        Long userId = UserHolder.getUserId();
        Integer commentType = 3;
        //1.删除comment表的互动数据
        Integer count = commentsServiceApi.delete(commentType, userId, id);
        //2.删除redis中的状态
        String redisKey = Constants.MOVEMENTS_INTERACT_KEY+id; //点赞和喜欢用同一个redis  key
        String hashKey = Constants.MOVEMENT_LOVE_HASHKEY+UserHolder.getUserId();
        redisTemplate.opsForHash().delete(redisKey,hashKey);
        return count;
    }
}
